import {
  LinearFilter,
  Mesh,
  NearestFilter,
  OrthographicCamera,
  PlaneGeometry,
  RGBAFormat,
  Scene,
  ShaderMaterial,
  StereoCamera,
  WebGLRenderTarget,
} from 'three'
import { version } from '../_polyfill/constants'

class ParallaxBarrierEffect {
  constructor(renderer) {
    const _camera = new OrthographicCamera(-1, 1, 1, -1, 0, 1)

    const _scene = new Scene()

    const _stereo = new StereoCamera()

    const _params = { minFilter: LinearFilter, magFilter: NearestFilter, format: RGBAFormat }

    const _renderTargetL = new WebGLRenderTarget(512, 512, _params)
    const _renderTargetR = new WebGLRenderTarget(512, 512, _params)

    const _material = new ShaderMaterial({
      uniforms: {
        mapLeft: { value: _renderTargetL.texture },
        mapRight: { value: _renderTargetR.texture },
      },

      vertexShader: [
        'varying vec2 vUv;',

        'void main() {',

        '	vUv = vec2( uv.x, uv.y );',
        '	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',

        '}',
      ].join('\n'),

      fragmentShader: [
        'uniform sampler2D mapLeft;',
        'uniform sampler2D mapRight;',
        'varying vec2 vUv;',

        'void main() {',

        '	vec2 uv = vUv;',

        '	if ( ( mod( gl_FragCoord.y, 2.0 ) ) > 1.00 ) {',

        '		gl_FragColor = texture2D( mapLeft, uv );',

        '	} else {',

        '		gl_FragColor = texture2D( mapRight, uv );',

        '	}',

        '	#include <tonemapping_fragment>',
        `	#include <${version >= 154 ? 'colorspace_fragment' : 'encodings_fragment'}>`,

        '}',
      ].join('\n'),
    })

    const mesh = new Mesh(new PlaneGeometry(2, 2), _material)
    _scene.add(mesh)

    this.setSize = function (width, height) {
      renderer.setSize(width, height)

      const pixelRatio = renderer.getPixelRatio()

      _renderTargetL.setSize(width * pixelRatio, height * pixelRatio)
      _renderTargetR.setSize(width * pixelRatio, height * pixelRatio)
    }

    this.render = function (scene, camera) {
      if (scene.matrixWorldAutoUpdate === true) scene.updateMatrixWorld()

      if (camera.parent === null && camera.matrixWorldAutoUpdate === true) camera.updateMatrixWorld()

      _stereo.update(camera)

      renderer.setRenderTarget(_renderTargetL)
      renderer.clear()
      renderer.render(scene, _stereo.cameraL)

      renderer.setRenderTarget(_renderTargetR)
      renderer.clear()
      renderer.render(scene, _stereo.cameraR)

      renderer.setRenderTarget(null)
      renderer.render(_scene, _camera)
    }
  }
}

export { ParallaxBarrierEffect }
